/**********************************************************************
 *                                                                    *
 * tgt - Tiny Graphics Toolbox                                        *
 *                                                                    *
 * Copyright (C) 2006-2008 Visualization and Computer Graphics Group, *
 * Department of Computer Science, University of Muenster, Germany.   *
 * <http://viscg.uni-muenster.de>                                     *
 *                                                                    *
 * This file is part of the tgt library. This library is free         *
 * software; you can redistribute it and/or modify it under the terms *
 * of the GNU Lesser General Public License version 2.1 as published  *
 * by the Free Software Foundation.                                   *
 *                                                                    *
 * This library is distributed in the hope that it will be useful,    *
 * but WITHOUT ANY WARRANTY; without even the implied warranty of     *
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the       *
 * GNU Lesser General Public License for more details.                *
 *                                                                    *
 * You should have received a copy of the GNU Lesser General Public   *
 * License in the file "LICENSE.txt" along with this library.         *
 * If not, see <http://www.gnu.org/licenses/>.                        *
 *                                                                    *
 **********************************************************************/

#include "tgt/quadric.h"
#include "tgt/memorymanager.h"
#include "tgt/guiapplication.h"
#include "tgt/glcanvas.h"
#include "tgt/qt/qtcanvas.h" // FIXME
#include "tgt/toolkitfactory.h"
#include "tgt/painter.h"
#include "tgt/stopwatch.h"

using namespace tgt;

GUIApplication* tgtApp;

GLCanvas* canvases[10] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
int currentCanvas;

void canvas(int, bool = true);
void activate(int);

Camera camera;

class MyEventListener : public EventListener {
    void keyEvent(KeyEvent *e);
}  eventListener;

class MyPainter : public Painter {
public:
    MyPainter(GLCanvas* canvas) : Painter(canvas) {};
    virtual void paint();
    virtual void init();
    virtual void sizeChanged(const ivec2& size);
};

void MyPainter::paint() {
    glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

    // make repaint noticable
    glFlush();                      // clear canvas
    Stopwatch sw;
    sw.start();
    while (sw.getRuntime() < 100);  // loop for 100 msec
    sw.stop();

    // set Camera (ratio might have been changed by othen canvases)
    getCamera()->setRatio((float) getCanvas()->getWidth()/getCanvas()->getHeight());
    getCamera()->look();

    // render sphere
    Sphere sphere(1., 64, 32);
    sphere.render();
}

void MyPainter::init() {
    glEnable(GL_DEPTH_TEST);
    glShadeModel(GL_SMOOTH);
    glEnable(GL_COLOR_MATERIAL);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);

    getCamera()->setPosition(vec3(0.f,0.f,3.f));

    glColor4f(1.f, 1.f, 0.f, 1.f);
}

void MyPainter::sizeChanged(const ivec2& size) {
    glViewport(0,0,size.x,size.y);
}

void MyEventListener::keyEvent(KeyEvent *e) {
    // only handle key-down events
//     if (e->pressed()) {
    if (!e->pressed()) {
        switch (e->keyCode()) {
        case KeyEvent::K_ESCAPE:
            delete canvases[currentCanvas];
            canvases[currentCanvas] = NULL;
            // make another canvas current
            {
                int id = 0;
                while (!canvases[id] && id < 10) {
                    id++;
                }
                if (id != 10) {
                    activate(id);
                } else {
                    // no more canvases open
                    e->accept();
                    tgtApp->quit();
                    return;
                }
            }
            break;
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
        {
            int num = e->keyCode() - '0';
            canvas(num);
            break;
        }
        default: ;
        }

        canvases[currentCanvas]->repaint();

        // to make sure no further EventListeners handles the event
        e->accept();
    }
}

// If init is true (which is the default when no 2nd argument is given) canvas and painter will be initialized. We need to skip initialization when creating out very first canvas and to it manually. So we will call canvas( ?, false) just once, within the main-method -- see below.
void canvas(int id, bool init) {
    if (id<0 || id>9) return;

    if (canvases[id] == NULL) {
        char title[ sizeof("(X) tgt Example: Canvases") ];
        sprintf(title, "(%d) tgt Example: Canvases", id);

        // create canvas with title and size representing canvas id
        // do not use double buffering to make repaints visible
        GLCanvas* canvas = ToolkitFactory::createCanvas(title,
                                                        ivec2(200+id*25, 225),
                                                        GLCanvas::RGBAD);
        tgtApp->addCanvas(canvas);

        if (init) {
            canvas->init();
        }

        canvas->setCamera(&camera);
        canvas->setPainter(new MyPainter(canvas), init);
        canvas->getEventHandler()->addListenerToFront(&eventListener);

        canvases[id] = canvas;
    }

    activate(id);
}

// makes the canvas with the given id the current canvas
void activate(int id) {
    if (canvases[currentCanvas]) {
        canvases[currentCanvas]->getGLFocus();
        glColor4f(1.f, 0.f, 0.f, 1.f);
        canvases[currentCanvas]->repaint();
    }
    canvases[id]->getGLFocus();
    glColor4f(1.f, 1.f, 0.f, 1.f);

    currentCanvas = id;
}

int main(int argc, char** argv) {
    
    std::cout
        << "tgt Sample Program: canvases" << std::endl
        << std::endl
        << "Manage several tgt GL windows." << std::endl
        << "(Sample is boring with SDLCanvas, as there can only be one at a time.)" << std::endl
        << std::endl
        << "Usage:" << std::endl
        << "1-9,0: Create/activate GL window" << std::endl
        << "Esc: destroy current GL window" << std::endl
        << std::endl
        << "When a window is destroied using the operating system window manager, we have no chance to notice in tgt. A window destroied using window manager instead of Esc key will disable that canvas number." << std::endl
        << std::endl;
    

    tgtApp = ToolkitFactory::createApplication(argc, argv);

    // at least one canvas must exist when calling tgtApp->init()
    canvas(1, false);

    tgtApp->init();

    // now we can prepare our OpenGL context
    canvases[1]->initPainter();    

    tgtApp->run();

    return 0;
}
